﻿'*******************************************************************************************
'* Copyright Brügmann Software GmbH, Papenburg
'* Author: Björn Kremer
'* Contact: codeplex<at>patorg.de
'* 
'* VB.CMIS is a VB.NET implementation of the Content Management Interoperability Services (CMIS) standard
'*
'* This file is part of VB.CMIS.
'* 
'* VB.CMIS is free software: you can redistribute it and/or modify
'* it under the terms of the GNU Lesser General Public License as published by
'* the Free Software Foundation, either version 3 of the License, or
'* (at your option) any later version.
'* 
'* VB.CMIS is distributed in the hope that it will be useful,
'* but WITHOUT ANY WARRANTY; without even the implied warranty of
'* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'* GNU Lesser General Public License for more details.
'* 
'* You should have received a copy of the GNU Lesser General Public License
'* along with VB.CMIS. If not, see <http://www.gnu.org/licenses/>.
'*******************************************************************************************
Imports System
Imports System.Runtime.Serialization
Imports System.Xml.Linq
Imports System.Xml.Serialization
Imports System.Xml

Namespace CMISObjects
   <XmlRoot("object", Namespace:=CmisNamespaceConstants.Cmisra)>
   Public MustInherit Class CmisObject
      Implements IXmlSerializable

      Public Property Id() As String
      Public Sub New()

      End Sub
      Public Sub New(id As String, properties() As CMISObjectModel.Properties.ICMISProperty, SingleTypeId As String, allowableActions As AllowableActions)
         Me.Id = id
         Me.Properties = properties
         Me.SingleTypeId = SingleTypeId
         Me.AllowableActions = allowableActions
      End Sub

#Region "Properties für XML Dokument"
      Public Property SingleTypeId As String



#End Region


      Public Property Properties() As CMISObjectModel.Properties.ICMISProperty()

      Public Property AllowableActions() As AllowableActions

      Public Property Relationships() As CmisRelationshipObject()

      Public Property ChangeEventInfo() As CmisChangeEvent

      Public Property Acl As Acl

      Public Property ExactAcl() As Nullable(Of Boolean)

      Public Property PolicyIds() As String()

      Public Property Renditions() As Rendition()


      Public Overridable Function GetAtomLinks(baseUri As Uri, RepositoryInfo As CMISObjectModel.ServiceDocument.RepositoryInfo) As List(Of CMISLink)
         Dim retVal As New List(Of CMISLink)
         Dim RepositoryId As String = RepositoryInfo.RepositoryId
         retVal.Add(New CMISLink(New Uri(baseUri, ServiceURIs.GetObjectBase.Replace("{repositoryId}", RepositoryId).Replace("{id}", Me.Id).TrimStart("/"c)), CmisAtomLinkConstants.Self, CmisContentTypeConstants.Entry))
         retVal.Add(New CMISLink(New Uri(baseUri, ServiceURIs.GetServiceDocumentById.Replace("{repositoryId}", RepositoryId).TrimStart("/"c)), CmisAtomLinkConstants.Service, CmisContentTypeConstants.Service))
         retVal.Add(New CMISLink(New Uri(baseUri, ServiceURIs.GetTypeDefinition.Replace("{repositoryId}", RepositoryId).Replace("{id}", SingleTypeId).TrimStart("/"c)), CmisAtomLinkConstants.DescribedBy, CmisContentTypeConstants.Entry))
         retVal.Add(New CMISLink(New Uri(baseUri, ServiceURIs.GetAllowableActions.Replace("{repositoryId}", RepositoryId).Replace("{id}", Me.Id).TrimStart("/"c)), CmisAtomLinkConstants.AllowableActions, CmisContentTypeConstants.AllowableActions))
         If RepositoryInfo.Capabilities.Acl <> ServiceDocument.RepositoryCapabilities.CapabilityAcl.None Then
            retVal.Add(New CMISLink(New Uri(baseUri, ServiceURIs.GetAcl.Replace("{repositoryId}", RepositoryId).Replace("{id}", Me.Id).TrimStart("/"c)), CmisAtomLinkConstants.Acl, CmisContentTypeConstants.Acl))
         End If
         retVal.Add(New CMISLink(New Uri(baseUri, ServiceURIs.GetAppliedPoliciesBase.Replace("{repositoryId}", RepositoryId).Replace("{id}", Me.Id).TrimStart("/"c)), CmisAtomLinkConstants.Policies, CmisContentTypeConstants.Feed))

         Return retVal
      End Function

      Public Function GetPropertyByDefinitionId(id As String, Optional caseSensitive As Boolean = True) As Properties.ICMISProperty
         If Not caseSensitive Then
            id = id.ToLowerInvariant
         End If
         If Properties Is Nothing Then
            Return Nothing
         End If
         For Each p As Properties.ICMISProperty In Properties
            Dim tmpId As String = p.PropertyDefinitionId
            If Not caseSensitive Then
               tmpId = tmpId.ToLowerInvariant
            End If
            If tmpId.Equals(id) Then
               Return p
            End If
         Next
         Return Nothing
      End Function


      Private Shared _propertyTypes As New Dictionary(Of String, Type)
      Shared Sub New()
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyBoolean)).ToLowerInvariant, GetType(Properties.CmisPropertyBoolean))
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyDateTime)).ToLowerInvariant, GetType(Properties.CmisPropertyDateTime))
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyDecimal)).ToLowerInvariant, GetType(Properties.CmisPropertyDecimal))
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyHtml)).ToLowerInvariant, GetType(Properties.CmisPropertyHtml))
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyId)).ToLowerInvariant, GetType(Properties.CmisPropertyId))
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyInteger)).ToLowerInvariant, GetType(Properties.CmisPropertyInteger))
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyString)).ToLowerInvariant, GetType(Properties.CmisPropertyString))
         _propertyTypes.Add(Common.GetXMLRootName(GetType(Properties.CmisPropertyUri)).ToLowerInvariant, GetType(Properties.CmisPropertyUri))
      End Sub



      Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
         Return Nothing
      End Function

      Public Sub ReadXml(reader As System.Xml.XmlReader) Implements System.Xml.Serialization.IXmlSerializable.ReadXml
         Dim doc As New System.Xml.XmlDocument()
         doc.Load(reader)

         Dim cmisRelationshipObjectXmlName As String = Common.GetXMLRootName(GetType(CmisRelationshipObject))
         Dim cmisRelationshipObjectNamespace As String = Common.GetXMLRootNamespace(GetType(CmisRelationshipObject))
         Dim node As System.Xml.XmlNode = Common.GetItemCaseInsensitiveFromXML(doc, Common.GetXMLRootName(Me.GetType).ToLowerInvariant)
         Me.ExactAcl = Nothing

         Dim relationShips As New List(Of CmisRelationshipObject)
         Dim renditions As New List(Of Rendition)
         Dim values As New List(Of String)
         For Each child As System.Xml.XmlNode In node.ChildNodes
            Dim lName As String = Common.GetNodeNameWithoutPrefix(child).ToLowerInvariant
            If lName.Equals("properties") Then
               ParsePropertiesNode(child)
            ElseIf lName.Equals("policyids") Then
               ParsePolicyIds(child)
            ElseIf lName.Equals("relationship") Then
               Dim serializer As New XmlSerializer(GetType(CmisRelationshipObject))
               Dim xml As String = "<" & cmisRelationshipObjectXmlName & " xmlns=""" & cmisRelationshipObjectNamespace & """>" & child.InnerXml & "</" & cmisRelationshipObjectXmlName & ">"
               Using stream As New IO.StringReader(xml)
                  relationShips.Add(DirectCast(serializer.Deserialize(stream), CmisRelationshipObject))
               End Using
            ElseIf lName.Equals("exactacl") Then
               Me.ExactAcl = Boolean.Parse(child.InnerText)
            ElseIf lName.Equals("allowableactions") Then
               Dim serializer As New XmlSerializer(GetType(AllowableActions))
               Using stream As New IO.StringReader(child.OuterXml)
                  Me.AllowableActions = DirectCast(serializer.Deserialize(stream), CMISObjects.AllowableActions)
               End Using
            ElseIf lName.Equals("rendition") Then
               Dim serializer As New XmlSerializer(GetType(Rendition))
               Using stream As New IO.StringReader(child.OuterXml)
                  renditions.Add(DirectCast(serializer.Deserialize(stream), CMISObjects.Rendition))
               End Using
            ElseIf lName.Equals("acl") Then
               Dim serializer As New XmlSerializer(GetType(Acl))
               Using stream As New IO.StringReader(child.OuterXml)
                  Me.Acl = DirectCast(serializer.Deserialize(stream), CMISObjects.Acl)
               End Using
            ElseIf lName.Equals("changeeventinfo") Then
               Dim serializer As New XmlSerializer(GetType(CmisChangeEvent))
               Using stream As New IO.StringReader(child.OuterXml)
                  Me.ChangeEventInfo = DirectCast(serializer.Deserialize(stream), CMISObjects.CmisChangeEvent)
               End Using
            End If
         Next

         Me.Relationships = relationShips.ToArray
         Me.Renditions = renditions.ToArray
      End Sub


      Private Sub ParsePolicyIds(policyIdsNode As XmlNode)
         Dim policyIds As New List(Of String)
         For Each child As XmlNode In policyIdsNode.ChildNodes
            If Common.GetNodeNameWithoutPrefix(child).ToLowerInvariant.Equals("id") Then
               policyIds.Add(child.InnerXml)
            End If
         Next
         Me.PolicyIds = policyIds.ToArray
      End Sub
      Private Sub ParsePropertiesNode(propertiesNode As XmlNode)
         Dim properties As New List(Of Properties.ICMISProperty)
         For Each node As XmlNode In propertiesNode.ChildNodes
            Dim obj As Type = GetPropertyTypeByName(Common.GetNodeNameWithoutPrefix(node))
            Dim serializer As New XmlSerializer(obj)
            Using stream As New IO.StringReader(node.OuterXml)
               properties.Add(DirectCast(serializer.Deserialize(stream), CMISObjectModel.Properties.ICMISProperty))
            End Using
         Next
         Me.Properties = properties.ToArray
      End Sub

      Private Function GetPropertyTypeByName(propertyName As String) As Type
         propertyName = propertyName.ToLowerInvariant
         Return _propertyTypes(propertyName)
      End Function

      Public Sub WriteXml(writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml
         Dim nsCore As String = CmisNamespaceConstants.Cmis

         'Element order seems to be relevant!!!

         writer.WriteStartElement("properties", nsCore)
         For Each cmisProperty As CMISObjectModel.Properties.ICMISProperty In Me.Properties
            Dim serializer As New XmlSerializer(cmisProperty.GetType)
            serializer.Serialize(writer, cmisProperty)
         Next
         writer.WriteEndElement() 'Element: properties

         If AllowableActions IsNot Nothing Then
            Dim serializer As New XmlSerializer(AllowableActions.GetType)
            serializer.Serialize(writer, AllowableActions)
         End If

         If Relationships IsNot Nothing AndAlso Relationships.Count > 0 Then
            For Each relation As CmisRelationshipObject In Relationships
               writer.WriteStartElement("relationship", nsCore)
               relation.WriteXml(writer)
               writer.WriteEndElement() 'Element: relationship
            Next
         End If

         If ChangeEventInfo IsNot Nothing Then
            Dim serializer As New XmlSerializer(ChangeEventInfo.GetType)
            serializer.Serialize(writer, ChangeEventInfo)
         End If

         If Acl IsNot Nothing Then
            Dim serializer As New XmlSerializer(Acl.GetType)
            serializer.Serialize(writer, Acl)
         End If

         If ExactAcl.HasValue Then
            writer.WriteElementString("exactACL", nsCore, ExactAcl.Value.ToString.ToLowerInvariant)
         End If

         If PolicyIds IsNot Nothing AndAlso PolicyIds.Count > 0 Then
            writer.WriteStartElement("policyIds", nsCore)
            For Each id As String In PolicyIds
               writer.WriteElementString("id", nsCore, id)
            Next
            writer.WriteEndElement() 'Element: policyIds
         End If

         If Renditions IsNot Nothing Then
            For Each r As Rendition In Renditions
               Dim serializer As New XmlSerializer(r.GetType)
               serializer.Serialize(writer, r)
            Next
         End If


      End Sub

   End Class

End Namespace